package com.handinglian.servicerecord.service.impl;

import cn.afterturn.easypoi.entity.vo.NormalExcelConstants;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.view.PoiBaseView;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.handinglian.common.utils.DateUtil;
import com.handinglian.common.utils.GeneralUtil;
import com.handinglian.common.utils.StringUtil;
import com.handinglian.employee.dto.DepartmentLevelDto;
import com.handinglian.employee.entity.Department;
import com.handinglian.employee.entity.Extension;
import com.handinglian.employee.entity.FileInfo;
import com.handinglian.employee.entity.UserInfo;
import com.handinglian.employee.service.DepartmentService;
import com.handinglian.employee.service.ExtensionService;
import com.handinglian.employee.service.FileInfoService;
import com.handinglian.employee.service.UserInfoService;
import com.handinglian.servicerecord.dto.*;
import com.handinglian.servicerecord.entity.CallRecord;
import com.handinglian.servicerecord.enums.RecordStateEnum;
import com.handinglian.servicerecord.mapper.CallRecordMapper;
import com.handinglian.servicerecord.param.CallRecordCreateParam;
import com.handinglian.servicerecord.service.CallRecordService;
import com.handinglian.servicerecord.service.MessageService;
import com.handinglian.servicerecord.service.MessageTemplateService;
import com.handinglian.task.entity.TaskUserCall;
import com.handinglian.task.enums.PhoneStateEnum;
import com.handinglian.task.service.TaskInfoService;
import com.handinglian.task.service.TaskUserCallService;
import com.handinglian.thirdparty.YunyiApiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@Slf4j
@Service("callRecordService")
public class CallRecordServiceImpl implements CallRecordService {
    @Autowired
    private CallRecordMapper callRecordMapper;
    @Autowired
    private FileInfoService fileInfoService;
    @Autowired
    private YunyiApiService yunyiApiService;
    @Autowired
    private ExtensionService extensionService;
    @Autowired
    @Lazy
    private TaskInfoService taskInfoService;
    @Autowired
    private MessageTemplateService templateService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private TaskUserCallService taskUserCallService;
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private SessionDAO sessionDAO;

    @Override
    public PageInfo<CallRecordDto> inquireCallRecordPageList(Integer userId, String startDate, String endDate, String userNameOrJobNum, String mobilePhone, String recordStatus, String phoneStatus, String hasRecords, String sortField, String sortOrder, Integer pageIndex, Integer pageSize) {
        List<Integer> recordStatusList = StringUtil.stringToIntegerList(recordStatus);
        List<Integer> phoneStatusList = StringUtil.stringToIntegerList(phoneStatus);
        List<Integer> hasRecordsList = StringUtil.stringToIntegerList(hasRecords);
        if (hasRecordsList.size() == 0||hasRecordsList.size() == 2){
            hasRecords = null;
        }

        Date sDate = StrUtil.isNotBlank(startDate)?cn.hutool.core.date.DateUtil.parseDateTime(startDate):null;
        Date eDate = StrUtil.isNotBlank(endDate)?cn.hutool.core.date.DateUtil.parseDateTime(endDate):null;

        UserInfo userInfo = userInfoService.get(userId);
        List<Integer> userIds = null;
        if (!userInfo.getJobNum().equals("admin")){
            String dataList = userInfo.getDataList();
            List<Integer> departmentIds = StringUtil.stringToIntegerList(dataList);
            List<UserInfo> userInfos =  userInfoService.list(departmentIds);
            userIds = userInfos.stream().map(userInfo1 -> userInfo1.getUserId()).collect(Collectors.toList());
        }

        pageIndex = pageIndex == null ? 1 : pageIndex;
        pageSize = pageSize == null ? 10 : pageSize;
        PageHelper.startPage(pageIndex, pageSize);
        List<CallRecordDto> callRecordList = callRecordMapper.inquireCallRecordPageList(userIds, userNameOrJobNum, mobilePhone, sDate, eDate, recordStatusList, phoneStatusList, hasRecords, sortField, sortOrder);
        callRecordList.forEach(callRecordDto -> {
            if (StringUtil.isBlank(callRecordDto.getRecordFile())){
                callRecordDto.setHasRecordFile(0);
            } else {
                callRecordDto.setHasRecordFile(1);
            }
        });

        List<Department> twoLevelDepartment = departmentService.listTwoLevelDepartment();
        List<DepartmentLevelDto> threeLevelDepartment = departmentService.listThreeLevelDepartment();
        for(CallRecordDto callRecordDto : callRecordList){
            //匹配员工归属县分
            for (Department department : twoLevelDepartment){
                if (callRecordDto.getDepartmentId().equals(department.getDepartmentId())){
                    callRecordDto.setUserCountyName(department.getDepartmentName());
                    break;
                }
            }
            if (StrUtil.isNotBlank(callRecordDto.getUserCountyName())){
                continue;
            }
            for (DepartmentLevelDto departmentLevelDto : threeLevelDepartment){
                if (callRecordDto.getDepartmentId().equals(departmentLevelDto.getDepartmentId())){
                    callRecordDto.setUserCountyName(departmentLevelDto.getParentName());
                    break;
                }
            }
        }

        return new PageInfo(callRecordList);
    }

    @Override
    public List<CallRecordAppDto> list(Integer answerState, Integer userId) {
        return callRecordMapper.list(answerState, userId);
    }

    @Override
    public CallRecordDetailDto loadCallRecordDetail(Integer callRecordId) {
        CallRecordDetailDto callRecordDetailDto = callRecordMapper.findOneByCallRecordId(callRecordId);
        if (StringUtil.isBlank(callRecordDetailDto.getRecordFile())){
            callRecordDetailDto.setHasRecordFile(0);
        } else {
            callRecordDetailDto.setHasRecordFile(1);
        }
        return callRecordDetailDto;
    }


    @Override
    public List<FileInfo> inquireCallRecordingList(List<String> callids) {
        List<String> fileUuids = callRecordMapper.findFileUuidBycCallidIn(callids);
        fileUuids = fileUuids.stream().filter(fileUuid -> StringUtil.isNotBlank(fileUuid)).collect(Collectors.toList());
        return fileInfoService.inquireFileInfoList(fileUuids);
    }

    @Override
    public FileInfo getFileInfo(String callid) {
        CallRecord callRecord = callRecordMapper.findOneByCallid(callid);
        if (StrUtil.isNotBlank(callRecord.getFileUuid())){
            return fileInfoService.loadFile(callRecord.getFileUuid());
        } else {
            return null;
        }

    }

    @Override
    @Transactional
    public String downloadRecording(String callid) throws IOException {
        FileInfo fileInfo = null;
        CallRecord callRecord = callRecordMapper.findOneByCallid(callid);
        if (StrUtil.isNotBlank(callRecord.getFileUuid())){
            fileInfo = fileInfoService.loadFile(callRecord.getFileUuid());
            return fileInfo.getFilePath();
        }

        String recordFile = callRecord.getRecordFile();
        Integer index = recordFile.lastIndexOf("/");
        String recordName = recordFile.substring(index+1);
        yunyiApiService.downloadRecording(callid, recordName);

        fileInfo = newFileInfo(recordName);
        fileInfoService.createFile(fileInfo);

        callRecord.setFileUuid(fileInfo.getFileUuid());
        callRecordMapper.updateByPrimaryKeySelective(callRecord);
        return "/"+recordName;
    }

    private FileInfo newFileInfo(String fileName) {
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileUuid(GeneralUtil.randomUUID());
        fileInfo.setFileName(fileName);
        fileInfo.setFilePath("/"+fileName);
        fileInfo.setCreateTime(new Date());
        return fileInfo;
    }

    @Override
    @Transactional
    public int createCallRecord(List<CallRecordCreateParam> callRecordCreateParams) {
        //筛选骚扰电话记录
        callRecordCreateParams = callRecordCreateParams.stream().filter(callRecordCreateParam -> StrUtil.isNotBlank(callRecordCreateParam.getStarTime())).collect(Collectors.toList());

        List<CallRecord> callRecordList = new ArrayList<>();
        List<String> callidDbList = callRecordMapper.findCallid();
        List<String> callidParamList = new ArrayList<>();
        callRecordCreateParams.forEach(callRecordCreateParam -> {
            callidParamList.add(callRecordCreateParam.getCallid());
        });

        //筛选需要添加的通话记录
        List<String> addList = GeneralUtil.getAddList(callidParamList, callidDbList);
        callRecordCreateParams = callRecordCreateParams.stream().filter(callRecordCreateParam -> addList.contains(callRecordCreateParam.getCallid())).collect(Collectors.toList());
        if (CollUtil.isEmpty(callRecordCreateParams)){
            return -1;
        }

        //给通话记录设置userId
        setUserId(callRecordCreateParams);

        callRecordCreateParams.forEach(callRecordCreateParam -> {
            CallRecord callRecord = convertToCallRecord(callRecordCreateParam);
            callRecordList.add(callRecord);
        });

        int amount = callRecordMapper.batchInsert(callRecordList);

        callRecordList.forEach(callRecord -> {
            Date startDate = callRecord.getStartTime();
            Date endDate = cn.hutool.core.date.DateUtil.offsetSecond(startDate, 1);
            startDate = cn.hutool.core.date.DateUtil.offsetSecond(startDate, -4);
            List<TaskUserCall> taskUserCalls = taskUserCallService.list(callRecord.getUserId(), callRecord.getCustomerNo(), startDate, endDate);
            if (CollectionUtil.isNotEmpty(taskUserCalls)){
                taskUserCalls.forEach(taskUserCall -> {
                    taskUserCall.setCallRecordId(callRecord.getCallRecordId());
                });
                taskUserCallService.updateBatch(taskUserCalls);
            }
        });

        return amount > 0?amount:-1;
    }

    private List<CallRecordCreateParam> setUserId(List<CallRecordCreateParam> callRecordCreateParams){
        callRecordCreateParams.forEach(callRecordCreateParam -> {
            if (callRecordCreateParam.getRecordStatus().equals(RecordStateEnum.CALL_IN.getKey())) {
                callRecordCreateParam.setExtensionNo(callRecordCreateParam.getCalledNO());
            } else if (callRecordCreateParam.getRecordStatus().equals(RecordStateEnum.CALL_OUT.getKey())){
                callRecordCreateParam.setExtensionNo(callRecordCreateParam.getCallerNO());
            } else {
                callRecordCreateParam.setExtensionNo(callRecordCreateParam.getCallerNO());
            }
        });

        List<String> extensionNo = callRecordCreateParams.stream().map(callRecordCreateParam -> callRecordCreateParam.getExtensionNo()).collect(Collectors.toList());
        List<Extension> extensions = extensionService.inquireUserIdByExtenNo(extensionNo);

        UserInfo userinfo = userInfoService.loadUserByJobNum("admin");
        callRecordCreateParams.forEach(callRecordCreateParam -> {
            extensions.forEach(extension -> {
                if (callRecordCreateParam.getExtensionNo().equals(extension.getExtenNo())){
                    Integer userId = extension.getUserId() == null?userinfo.getUserId():extension.getUserId();
                    callRecordCreateParam.setUserId(userId);
                }
            });
        });
        return callRecordCreateParams;
    }

    private CallRecord convertToCallRecord(CallRecordCreateParam callRecordCreateParam) {
        CallRecord callRecord = new CallRecord();
        callRecord.setStartTime(DateUtil.from(callRecordCreateParam.getStarTime()));

        Date endDate = DateUtil.addSeconds(DateUtil.from(callRecordCreateParam.getStarTime()),callRecordCreateParam.getDurationTime());
        callRecord.setEndTime(endDate);

        callRecord.setCallerNo(callRecordCreateParam.getCallerNO());
        callRecord.setCalledNo(callRecordCreateParam.getCalledNO());
        if (callRecordCreateParam.getRecordStatus().equals(RecordStateEnum.CALL_IN.getKey())){
            callRecord.setCustomerNo(callRecordCreateParam.getCallerNO());
        } else if (callRecordCreateParam.getRecordStatus().equals(RecordStateEnum.CALL_OUT.getKey())){
            callRecord.setCustomerNo(callRecordCreateParam.getCalledNO());
        } else {
            callRecord.setCustomerNo(callRecord.getCalledNo());
        }
        callRecord.setDurationTime(callRecordCreateParam.getDurationTime());
        callRecord.setRecordStatus(callRecordCreateParam.getRecordStatus());
        Integer phoneStatus = callRecordCreateParam.getDurationTime() == 0?1:2;
        callRecord.setPhoneStatus(phoneStatus);
        callRecord.setRecordFile(callRecordCreateParam.getRecordFile());
        callRecord.setCallid(callRecordCreateParam.getCallid());
        callRecord.setUserId(callRecordCreateParam.getUserId());
        callRecord.setCreateTime(new Date());
        return callRecord;
    }


    @Override
    public List<String> inquireReqidByStartTime(String startDate, String endDate) {
        return callRecordMapper.findReqidByStartTimeBetween(DateUtil.from(startDate), DateUtil.from(endDate));
    }

    @Override
    @Transactional
    public int createCallRecordBatch(List<CallRecord> callRecordList) {
        return callRecordMapper.batchInsert(callRecordList);
    }

    @Override
    public int countTaskCallNum(List<Integer> taskUserIds) {
        return callRecordMapper.countTaskCallNum(taskUserIds);
    }

    @Override
    public int countTaskAnswerNum(List<Integer> taskUserIds) {
        return callRecordMapper.countTaskAnswerNum(taskUserIds);
    }

    @Override
    public List<CallRecord> inquireCallRecordByUserId(Collection userIds) {
        return callRecordMapper.findCallRecordByUserIdIn(userIds);
    }

    @Override
    public List<CallRecord> listTaskCallRecord(Integer taskId) {
        List<TaskUserCall> taskUserCalls = taskUserCallService.list(taskId);
        List<Integer> callRecordIds = taskUserCalls.stream().map(taskUserCall -> taskUserCall.getCallRecordId()).collect(Collectors.toList());
        if (CollUtil.isEmpty(callRecordIds)){
            return new ArrayList<>();
        }
        return callRecordMapper.findByCallRecordIdIn(callRecordIds);
    }

    @Override
    public List<CallRecord> inquireAnswerRecordByUserId(Collection userIds) {
        return callRecordMapper.findAnswerRecordByUserIdIn(userIds);
    }

    @Override
    public List<CallRecord> listAnswerRecord(Integer taskId) {
        List<TaskUserCall> taskUserCalls = taskUserCallService.list(taskId);
        List<Integer> callRecordIds = taskUserCalls.stream().map(taskUserCall -> taskUserCall.getCallRecordId()).collect(Collectors.toList());
        if (CollUtil.isEmpty(callRecordIds)){
            return new ArrayList<>();
        }
        return callRecordMapper.findAnswer(callRecordIds);
    }

    @Override
    public CallRecord loadCallRecordByUserIdCustomerNo(Integer userId, String customerNo, Date operationTime) {
        Date startTime = DateUtil.addSeconds(operationTime, -3);
        Date endDate = DateUtil.addSeconds(operationTime, 3);
        return callRecordMapper.loadCallRecordByUserIdCustomerNo(userId, customerNo, startTime, endDate);
    }

    @Override
    public List<CallRecord> inquireCallRecordByCustomerNo(Integer userId, String customerNo) {
        return callRecordMapper.findByCustomerNoAndUserId(customerNo, userId);
    }

    @Override
    public List<CallRecord> inquireAnswerRecordByCustomerNo(Integer userId, String customerNo) {
        return callRecordMapper.findAnswerRecordByCustomerNoAndUserId(userId, customerNo);
    }

    @Override
    public IndexDto getIndex() throws ExecutionException, InterruptedException {
        Future<Integer> futureTaskCount = taskInfoService.count();
        Future<Integer> futureExecutoryCount = taskInfoService.countExecutory();
        Future<Integer> futureReadyAssignCount = taskInfoService.countReadyAssign();
        Future<Integer> futureReadyStartCount = taskInfoService.countReadyStart();
        Future<Integer> futureOverdueCount = taskInfoService.countOverdue();
        Future<Integer> futureTemplateCount = templateService.count();
        Future<Integer> futureUserCount = userInfoService.count();
        Future<Integer> futureSystemUserCount = userInfoService.countSystemUser();
        Future<Integer> futureCustomerCount = taskInfoService.countCustomer();

        Future<List<TaskIndexDto>> futureTaskIndexDtos = taskInfoService.listTaskIndexDto();
        DateTime now = DateTime.now();
        int year = now.year();
        Date startDate = cn.hutool.core.date.DateUtil.parseDateTime(year+"-01-01 00:00:00");
        Date endDate = cn.hutool.core.date.DateUtil.parseDateTime(year+"-12-31 23:59:59");
        Future<List<MessageIndexDto>> futureMessageIndexDtos = messageService.countMessageRecord(startDate, endDate);
        List<CallIndexDto> callIndexDtos = callRecordMapper.countCallRecord(startDate, endDate);
        Collection<Session> sessions = sessionDAO.getActiveSessions();
        Integer countCallOut = callRecordMapper.countCallout();
        Integer countCallOutEveryday = callRecordMapper.countCalloutEveryday();

        IndexDto indexDto = new IndexDto();
        indexDto.setTaskCount(futureTaskCount.get());
        indexDto.setTaskReadyAssignCount(futureReadyAssignCount.get());
        indexDto.setTaskReadyStartCount(futureReadyStartCount.get());
        indexDto.setTaskOverdueCount(futureOverdueCount.get());
        indexDto.setTaskExecutoryCount(futureExecutoryCount.get());
        indexDto.setTaskIndexDtos(futureTaskIndexDtos.get());
        indexDto.setUserCount(futureUserCount.get());
        indexDto.setMessageTemplateCount(futureTemplateCount.get());
        indexDto.setSystemUserCount(futureSystemUserCount.get());
        indexDto.setCallIndexDtos(callIndexDtos);
        indexDto.setMessageIndexDtos(futureMessageIndexDtos.get());
        indexDto.setCustomerCount(futureCustomerCount.get());
        indexDto.setOnlineUserCount(sessions.size());
        indexDto.setCallCount(countCallOut);
        indexDto.setCallCountEveryday(countCallOutEveryday);
        return indexDto;
    }

    @Override
    public CallRecord get(Integer callRecordId) {
        return callRecordMapper.selectByPrimaryKey(callRecordId);
    }

    @Override
    public void exportCallRecord(ModelMap map, HttpServletRequest request, HttpServletResponse response) {
        List<CallRecordExcel> callRecordExcels = listCallRecordExcel();
        List<Department> twoLevelDepartment = departmentService.listTwoLevelDepartment();
        List<DepartmentLevelDto> threeLevelDepartment = departmentService.listThreeLevelDepartment();

        for(CallRecordExcel callRecordExcel : callRecordExcels){
            //匹配员工归属县分
            for (Department department : twoLevelDepartment){
                if (callRecordExcel.getDepartmentId().equals(department.getDepartmentId())){
                    callRecordExcel.setUserCountyName(department.getDepartmentName());
                    callRecordExcel.setUserHallName("");
                    break;
                }
            }
            if (StrUtil.isNotBlank(callRecordExcel.getUserCountyName())){
                continue;
            }
            //匹配员工归属营业厅
            for (DepartmentLevelDto departmentLevelDto : threeLevelDepartment){
                if (callRecordExcel.getDepartmentId().equals(departmentLevelDto.getDepartmentId())){
                    callRecordExcel.setUserHallName(departmentLevelDto.getDepartmentName());
                    callRecordExcel.setUserCountyName(departmentLevelDto.getParentName());
                    break;
                }
            }
        }

        callRecordExcels.forEach(callRecordExcel -> {
            String phoneStatus = PhoneStateEnum.valueOfKey(Integer.valueOf(callRecordExcel.getPhoneStatus())).getDescription();
            callRecordExcel.setPhoneStatus(phoneStatus);
            String recordStatus = RecordStateEnum.valueOfKey(Integer.valueOf(callRecordExcel.getRecordStatus())).getDescription();
            callRecordExcel.setRecordStatus(recordStatus);
            String recordFile = callRecordExcel.getRecordFile();
            recordFile = StrUtil.isBlank(recordFile)?"无":"有";
            callRecordExcel.setRecordFile(recordFile);
        });

        ExportParams params = new ExportParams("通话记录", "通话记录", ExcelType.XSSF);
        map.put(NormalExcelConstants.DATA_LIST, callRecordExcels);
        map.put(NormalExcelConstants.CLASS, CallRecordExcel.class);
        map.put(NormalExcelConstants.PARAMS, params);
        map.put(NormalExcelConstants.FILE_NAME, "通话记录");
        PoiBaseView.render(map, request, response, NormalExcelConstants.EASYPOI_EXCEL_VIEW);
    }

    public List<CallRecordExcel> listCallRecordExcel() {
        return callRecordMapper.findCallRecordExcel();
    }
}
